package com.coolw.test.sftp.pool;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.Map;

/**
 * sftp 工具类
 *
 * @author coolw
 * @date 2025/8/12 11:30
 */
@Service
public class SftpService {

    private final Map<String, GenericObjectPool<ChannelSftp>> sftpPools;

    public SftpService(Map<String, GenericObjectPool<ChannelSftp>> sftpPools) {
        this.sftpPools = sftpPools;
    }

    /**
     * 上传文件到指定SFTP服务器
     *
     * @param serverId       服务器标识
     * @param remoteDir      远程目录
     * @param remoteFileName 远程文件名
     * @param inputStream    输入流
     */
    public void uploadFile(String serverId, String remoteDir, String remoteFileName, InputStream inputStream)
            throws Exception {
        GenericObjectPool<ChannelSftp> pool = getPool(serverId);
        ChannelSftp channel = null;

        try {
            // 从连接池借用对象（如果获取不到对象：建议优雅处理池耗尽的情况，可以尝试再次从连接池获取，或者直连接sftp服务器等）
            channel = pool.borrowObject();

            // 创建远程目录
            createRemoteDir(channel, remoteDir);

            // 上传文件
            channel.cd(remoteDir);
            channel.put(inputStream, remoteFileName);

        } finally {
            // 将对象归还连接池
            if (channel != null) {
                pool.returnObject(channel);
            }
        }
    }

    /**
     * 从指定SFTP服务器下载文件
     */
    public InputStream downloadFile(String serverId, String remoteFilePath) throws Exception {
        GenericObjectPool<ChannelSftp> pool = getPool(serverId);
        ChannelSftp channel = null;

        try {
            channel = pool.borrowObject();
            return channel.get(remoteFilePath);
        } finally {
            if (channel != null) {
                pool.returnObject(channel);
            }
        }
    }

    /**
     * 删除指定SFTP服务器上的文件
     */
    public void deleteFile(String serverId, String remoteFilePath) throws Exception {
        GenericObjectPool<ChannelSftp> pool = getPool(serverId);
        ChannelSftp channel = null;

        try {
            channel = pool.borrowObject();
            channel.rm(remoteFilePath);
        } finally {
            if (channel != null) {
                pool.returnObject(channel);
            }
        }
    }

    /**
     * 创建远程目录（支持多级目录）
     */
    private void createRemoteDir(ChannelSftp channel, String remoteDir) throws SftpException {
        String[] dirs = remoteDir.split("/");
        String currentDir = "";

        for (String dir : dirs) {
            if (dir.isEmpty()) {
                continue;
            }

            currentDir += "/" + dir;
            try {
                channel.cd(currentDir);
            } catch (SftpException e) {
                if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                    channel.mkdir(currentDir);
                    channel.cd(currentDir);
                } else {
                    throw e;
                }
            }
        }
    }

    /**
     * 获取指定服务器的连接池
     */
    private GenericObjectPool<ChannelSftp> getPool(String serverId) {
        GenericObjectPool<ChannelSftp> pool = sftpPools.get(serverId);
        if (pool == null) {
            throw new IllegalArgumentException("未找到ID为[" + serverId + "]的SFTP服务器配置");
        }
        return pool;
    }

    /**
     * 检查目录是否已存在
     * 1.如果目录不存在会报SftpException，id=2 {@link ChannelSftp#SSH_FX_NO_SUCH_FILE}，返回false
     * 2.其他异常，直接抛出
     */
    private boolean checkIfDirExist(ChannelSftp channel, String remoteDir) throws SftpException {
        try {
            SftpATTRS stat = channel.stat(remoteDir);
            return stat.isDir();
        } catch (SftpException e) {
            if (e.id != ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                throw e;
            }
            return false;
        }
    }
}
